//
//  MKImageManager.m
//  MKWebImage
//
//  Created by lily on 17/1/1.
//  Copyright © 2017年 lily. All rights reserved.
//

#import "MKImageManager.h"
#import "MKImageDownloader.h"
#import "MKImageCache.h"
#import <CommonCrypto/CommonCrypto.h>

@interface MKImageManager(){
   
}

//下载队列 存储当前正在执行下载操作的downloader
@property (nonatomic, strong) NSMutableArray *loaderQueue;

//准备队列 存储超过下载上限后的downloader，随时准备加入到下载队列下载图片
@property (nonatomic, strong) NSMutableArray *loaderPreviousQueue;

//最大同时请求数
@property int maxImageDownloadCount;

@end

@implementation MKImageManager

+ (MKImageManager *)shareInstance {
    static dispatch_once_t onceToken;
    static MKImageManager *instance = nil;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
        instance.maxImageDownloadCount = 5;
    });
    return instance;
}

- (void)addDownloaderToQueue:(MKImageDownloader *)loader {
    //3. 如果大于最大请求数，加入到准备队列中, 如果小于，加入到加载队列中并开始下载图片
    if (self.loaderQueue.count >= self.maxImageDownloadCount) {
        [self.loaderPreviousQueue addObject:loader];
        NSLog(@"超过最大请求数，先放入准备队列中, %d", (int)self.loaderPreviousQueue.count);
    } else {
        
        [self.loaderQueue addObject:loader];
        [loader.task resume];
        NSLog(@"begin download image... %d", (int)self.loaderQueue.count);
    }
}



//下载完成后，从下载队列中移除
- (void)removeLoaderFromQueue:(MKImageDownloader *)loader {
    if (!loader) {
        return;
    }
    if ([self.loaderQueue containsObject:loader]) {
        [self.loaderQueue removeObject:loader];
        [loader.task cancel];
        loader = nil;
    }
}

//检查准备队列中是否有数据，有则将其放到下载队列中加载图片
- (void)checkPreviousQueue {
    if (self.loaderQueue.count < self.maxImageDownloadCount && self.loaderPreviousQueue.count > 0) {
        NSLog(@"从准备队列中获取数据，加入到下载队列中");
        MKImageDownloader *loader = [self.loaderPreviousQueue firstObject];
        [self.loaderPreviousQueue removeObjectAtIndex:0];
        [self addDownloaderToQueue:loader];
    }
}

- (void)removeLoader:(MKImageDownloader *)loader {
    if (!loader) {
        return;
    }
    [self removeLoaderFromQueue:loader];
    [self removeLoaderFromPreviousQueue:loader];
}

- (void)removeLoaderFromPreviousQueue:(MKImageDownloader *)loader {
    if (!loader) {
        return;
    }
    if ([self.loaderPreviousQueue containsObject:loader]) {
        [self.loaderPreviousQueue removeObject:loader];
        loader = nil;
    }
}

- (MKImageDownloader *)downloadWithUrl:(NSString *)url option:(MKLoadOptions)options complete:(void(^)(UIImage *image, BOOL cache, NSError *error))complete {
    if (!url) {
        NSLog(@"url 不能为空");
        return nil;
    }
    
    NSString *key = [self md5:url];
    
    UIImage *img = nil;
    if (!(options & MKLoadIgnoreMemoryOption)) {
        //需要从内存中读取数据
        img = [MKImageCache memoryImageForKey:key];
        
    }
    
    if (!img) {
        //需要从本地种读取数据
        if (!(options & MKLoadIgnoreDiskOption)) {
            img = [MKImageCache diskImageForKey:key];
            if (img) {
                NSLog(@"从本地缓存读取数据");
                [MKImageCache saveImageToMemory:img forKey:key];
            }
        }
    } else {
        NSLog(@"从内存中读取数据");
    }
    
    if (img) {
        if (complete) {
            complete(img, YES, nil);
        }
        return nil;
    }
    __weak typeof(self) weakself = self;
    //1. 创建loader
    MKImageDownloader *loader = [[MKImageDownloader alloc] initWithUrl:url complete:^(UIImage *image, NSError *error, MKImageDownloader *loader) {
        //4. 下载完成后，从下载队列中移除
        [weakself removeLoaderFromQueue:loader];
        
        //5. 检查准备队列中是否有数据，有则将其放到下载队列中加载图片
        [weakself checkPreviousQueue];
        
        //将图片保存到本地缓存和内存缓存
        if (image) {
            [MKImageCache saveImageToDisk:image forKey:key];
            [MKImageCache saveImageToMemory:image forKey:key];
        }
        
        if (complete) {
            complete(image, NO, error);
        }
    }];
    
    //2. 把loader加入到请求队列中，开始加载图片
    [self addDownloaderToQueue:loader];
    
    return loader;
}

- (NSString *)md5:(NSString *)str
{
    const char *cStr = [str UTF8String];
    unsigned char result[16];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
    return [NSString stringWithFormat:
            @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
            result[0], result[1], result[2], result[3],
            result[4], result[5], result[6], result[7],
            result[8], result[9], result[10], result[11],
            result[12], result[13], result[14], result[15]
            ];
}

- (NSMutableArray *)loaderQueue {
    if (!_loaderQueue) {
        _loaderQueue = [NSMutableArray array];
    }
    return _loaderQueue;
}

- (NSMutableArray *)loaderPreviousQueue {
    if (!_loaderPreviousQueue) {
        _loaderPreviousQueue = [NSMutableArray array];
    }
    return _loaderPreviousQueue;
}

@end
